import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Transport {
	
	public static List<State> getNextValidStates(Problem p, State currentState)
	{
		ArrayList<State> validNextState = new ArrayList<State>();
		int whereIsShip = currentState.StateInternalProperties.get("Ship");
		
		// States for One Person
		getValidStatesOnePerson(p, currentState, validNextState, whereIsShip);
		
		// States for Two Person
		getValidStatesTwoPerson(p, currentState, validNextState, whereIsShip);
		
		// Return all ValidStats
		return validNextState;
	}

	private static void getValidStatesTwoPerson(Problem p, State currentState,
			ArrayList<State> validNextState, int whereIsShip) {
		if (p.whoCanDrive == "all")
		{
			for (String key : currentState.StateInternalProperties.keySet()) {
				for (String key2 : currentState.StateInternalProperties.keySet()) {
					State newState = new State();
					newState.StateInternalProperties = new HashMap<String, Integer>();
					
					// Get next allocation
					int allocation = key == key2 ? 2 : 1;
					
					// Two person ship from right to left.
					if (whereIsShip == 0 && key != "Ship" && key2 != "Ship" 
							&& currentState.StateInternalProperties.get(key) + allocation <= p.maxMember
							&& currentState.StateInternalProperties.get(key2) + allocation <= p.maxMember)
					{
						newState.StateInternalProperties.putAll(currentState.StateInternalProperties);
						newState.StateInternalProperties.put(key, currentState.StateInternalProperties.get(key) + allocation);
						newState.StateInternalProperties.put(key2, currentState.StateInternalProperties.get(key2) + allocation);
						newState.StateInternalProperties.put("Ship", 1);
					}
					// Two person ship from left to right.
					if (whereIsShip == 1 && key != "Ship" && key2 != "Ship" 
							&& currentState.StateInternalProperties.get(key) - allocation >= 0
							&& currentState.StateInternalProperties.get(key2) - allocation >= 0)
					{
						newState.StateInternalProperties.putAll(currentState.StateInternalProperties);
						newState.StateInternalProperties.put(key, currentState.StateInternalProperties.get(key) - allocation);
						newState.StateInternalProperties.put(key2, currentState.StateInternalProperties.get(key2) - allocation);
						newState.StateInternalProperties.put("Ship", 0);
					}
					
					if (!p.invalidStates.contains(newState) && !newState.StateInternalProperties.isEmpty() && !validNextState.contains(newState))
					{
						validNextState.add(newState);
					}
				}
			}
		}
		else if (p.whoCanDrive == "Farmer")
		{
			for (String key : currentState.StateInternalProperties.keySet()) {
				State newState = new State();
				newState.StateInternalProperties = new HashMap<String, Integer>();
				
				// One person ship from right to left.
				if (whereIsShip == 0 && key != "Ship" && key != "Farmer" 
						&& currentState.StateInternalProperties.get(key) + 1 <= p.maxMember)
				{
					newState.StateInternalProperties.putAll(currentState.StateInternalProperties);
					newState.StateInternalProperties.put(key, currentState.StateInternalProperties.get(key) + 1);
					newState.StateInternalProperties.put("Ship", 1);
					newState.StateInternalProperties.put("Farmer", 1);
				}
				// One person ship from left to right.
				if (whereIsShip == 1 && key != "Ship" && key != "Farmer" 
						&& currentState.StateInternalProperties.get(key) - 1 >= 0)
				{
					newState.StateInternalProperties.putAll(currentState.StateInternalProperties);
					newState.StateInternalProperties.put(key, currentState.StateInternalProperties.get(key) - 1);
					newState.StateInternalProperties.put("Ship", 0);
					newState.StateInternalProperties.put("Farmer", 0);
				}
				
				if (!p.invalidStates.contains(newState) && !newState.StateInternalProperties.isEmpty())
				{
					validNextState.add(newState);
				}
			}
		}
	}

	private static void getValidStatesOnePerson(Problem p, State currentState,
			ArrayList<State> validNextState, int whereIsShip) {
		if (p.whoCanDrive == "all")
		{
			for (String key : currentState.StateInternalProperties.keySet()) {
				State newState = new State();
				newState.StateInternalProperties = new HashMap<String, Integer>();
				
				// One person ship from right to left.
				if (whereIsShip == 0 && key != "Ship" && currentState.StateInternalProperties.get(key) + 1 <= p.maxMember)
				{
					newState.StateInternalProperties.putAll(currentState.StateInternalProperties);
					newState.StateInternalProperties.put(key, currentState.StateInternalProperties.get(key) + 1);
					newState.StateInternalProperties.put("Ship", 1);
				}
				// One person ship from left to right.
				if (whereIsShip == 1 && key != "Ship" && currentState.StateInternalProperties.get(key) - 1 >= 0)
				{
					newState.StateInternalProperties.putAll(currentState.StateInternalProperties);
					newState.StateInternalProperties.put(key, currentState.StateInternalProperties.get(key) - 1);
					newState.StateInternalProperties.put("Ship", 0);
				}
				
				if (!p.invalidStates.contains(newState) && !newState.StateInternalProperties.isEmpty())
				{
					validNextState.add(newState);
				}
			}
		}
		else if (p.whoCanDrive == "Farmer")
		{
			State newState = new State();
		
			newState.StateInternalProperties = new HashMap<String, Integer>();
			newState.StateInternalProperties.putAll(currentState.StateInternalProperties);
			newState.StateInternalProperties.put("Farmer", currentState.StateInternalProperties.get("Farmer") == 1 ? 0 : 1);
			newState.StateInternalProperties.put("Ship", whereIsShip == 1 ? 0 : 1);
			
			if (!p.invalidStates.contains(newState) && !newState.StateInternalProperties.isEmpty())
			{
				validNextState.add(newState);
			}
		}
	}
}
